import os

from flask import Flask, request, jsonify
import matplotlib.pyplot as plt
from 异常点检测.anomaly_detection import outlier_detection  # 确保导入的路径正确
from 相关性分析.below_triangle import draw_scatter  # 热力图散点图 下三角
from 相关性分析.upper_triangular import draw_heatmap  # 上三角
from 相关性分析.upper_below import draw_combined_heatmap_scatter
from 性能预测模块.integrat_enhance import ensemble_model #集成增强模型
from  PCA降维.pca import perform_pca        #PCA
from 重要性排序.XGB import  plot_feature_importance        #XGB
from  重要性排序.RF import  plot_feature_importance_rf #RF

# 设置 Matplotlib 中文支持
plt.rcParams['font.sans-serif'] = ['SimSun']  # 使用宋体，确保中文显示正常
plt.rcParams['font.serif'] = ['Times New Roman']  # 英文字体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
app = Flask(__name__)
#异常点检测
@app.route('/unusualDetection', methods=['POST'])
def detect_outliers():
    try:
        data = request.get_json()
        print("收到请求数据:", data)

        xlsxFile = data.get("xlsxFile")
        feature1 = data.get("feature1")
        feature2 = data.get("feature2")
        selectFeature = data.get("selectFeature")

        # 获取异常点行号 + 异常点数量 + 正常点数量
        anomaly_rows, num_anomalies, num_normals, output_file = outlier_detection(
            xlsxFile, feature1, feature2, selectFeature
        )

        # 构造返回 JSON
        response_data = {
            "message": "检测完成",
            "code": "200",
            "data": {
                "anomalyRows": anomaly_rows,  # 异常行号集合
                "numAnomalies": int(num_anomalies),  # 异常点数量
                "numNormals": int(num_normals),  # 正常点数量
                "imagePath": output_file  # 结果图像路径
            }
        }

        print("最终返回数据:", response_data)
        return jsonify(response_data)

    except Exception as e:
        print("检测过程中发生错误:", str(e))
        return jsonify({
            "error": str(e),
            "message": "检测失败",
            "code": "501",
        })

# 热力图散点图 下三角
@app.route('/below/namic', methods=['POST'])
def detect_outliers_heatmap():
    try:
        data = request.get_json()  # 获取 JSON 数据
        print("收到请求数据:", data)

        # 读取参数
        xlsxFile = data.get("xlsxFile")
        selectFeature = data.get("selectFeature")

        if not xlsxFile or not selectFeature:
            return jsonify({"error": "缺少 xlsxFile 或 selectFeature 参数"}), 400

        # 调用热力图绘制函数
        output_path = draw_scatter(xlsxFile, selectFeature)
        # 构造符合新格式的 JSON 响应
        response_data = {
            "message": "检测完成",
            "code": "200",
            "data": {
                "imagePath": output_path  # 图像文件路径
            }
        }

        return jsonify(response_data)

    except Exception as e:
        print("绘制热力图时发生错误:", str(e))
        return jsonify({"error": str(e)}), 500

# 热力图散点图 上三角
@app.route('/upper/namic', methods=['POST'])
def detect_upper_heatmap():
    try:
        data = request.get_json()
        print("收到请求数据:", data)

        # 获取参数
        xlsxFile = data.get("xlsxFile")
        selectFeature = data.get("selectFeature")

        if not xlsxFile or not selectFeature:
            return jsonify({"error": "缺少 xlsxFile 或 selectFeature 参数"}), 400

        # 调用热力图绘制函数
        correlation_data, output_path = draw_heatmap(xlsxFile, selectFeature)

        # 重新格式化数据
        formatted_data = []
        for item in correlation_data:
            formatted_data.append({
                "relatedOne": item["关联方"][0],
                "relatedTwo": item["关联方"][1],
                "correlation": "正" if item["值"] > 0 else "负",
                "value": item["值"]
            })

        # 构造符合新格式的 JSON 响应
        response_data = {
            "message": "检测完成",
            "code": "200",
            "data": {
                "imagePath": output_path,  # 图像文件路径
                "result": formatted_data  # 重新格式化的数据
            }
        }

        print("最终返回数据:", response_data)
        return jsonify(response_data)  # 修正缩进，确保 return 语句正确执行

    except Exception as e:
        print("绘制热力图时发生错误:", str(e))
        return jsonify({"error": str(e), "message": "检测失败", "code": "500"}), 500



# 热力图散点图 全三角
@app.route('/upper/below', methods=['POST'])
def detect_upper_below():
    try:
        data = request.get_json()
        print("收到请求数据:", data)

        # 获取参数
        xlsxFile = data.get("xlsxFile")
        selectFeature = data.get("selectFeature")

        if not xlsxFile or not selectFeature:
            return jsonify({"error": "缺少 xlsxFile 或 selectFeature 参数"}), 400

        # 调用热力图+散点图绘制函数
        output_path = draw_combined_heatmap_scatter(xlsxFile, selectFeature)

        # 构造符合新格式的 JSON 响应
        response_data = {
            "message": "检测完成",
            "code": "200",
            "data": {
                "imagePath": output_path  # 图像文件路径
            }
        }

        print("最终返回数据:", response_data)
        return jsonify(response_data)  # 修正缩进，确保 return 正确执行

    except Exception as e:
        print("绘制热力图时发生错误:", str(e))
        return jsonify({
            "error": str(e),
            "message": "检测失败",
            "code": "500"
        }), 500


# 热力图散点图 接口整合
@app.route('/full/heatmap', methods=['POST'])
def detect_upper_belowp():
    try:
        data = request.get_json()
        print("收到请求数据:", data)

        # 获取参数
        xlsxFile = data.get("xlsxFile")
        selectFeature = data.get("selectFeature")

        if not xlsxFile or not selectFeature:
            return jsonify({"error": "缺少 xlsxFile 或 selectFeature 参数"}), 400

        # 全三角
        output_path_upper_below = draw_combined_heatmap_scatter(xlsxFile, selectFeature)
        # 下三角
        output_path_below = draw_scatter(xlsxFile, selectFeature)
         #上三角
        output_path, output_file = draw_heatmap(xlsxFile, selectFeature)

        correlation_data = output_path  # 假设这是相关性数据
        # 重新格式化数据
        formatted_data = []
        for item in correlation_data:
            formatted_data.append({
                "relatedOne": item["关联方"][0],
                "relatedTwo": item["关联方"][1],
                "correlation": "正" if item["值"] > 0 else "负",
                "value": item["值"]
            })


        return jsonify({
            "message": "热力图生成完成",
            "code": "200",
            "upperBelow": output_path_upper_below,  # 全三角
            "below": output_path_below  ,# 下三角
            "data": formatted_data,  # 上三角数据
            "upper": output_file #上三角路径
        })

    except Exception as e:
        print("绘制热力图时发生错误:", str(e))
        return jsonify({"error": str(e)}), 500






# ----------------------------------------------------------------------------------------------------------------------------





#PCA
@app.route('/pca', methods=['POST'])
def detect_pca():
    try:
        data = request.get_json()
        if not data:
            return jsonify({"error": "请求数据为空", "code": "400"}), 400

        # 获取参数
        csv_file = data.get("urlFile")
        target_column = data.get("targetColumn")
        n_components = data.get("nComponents", 2)



        if not csv_file or not os.path.exists(csv_file):
            return jsonify({"error": "文件不存在或路径错误", "code": "400"}), 400

        # 运行 PCA 并获取结果
        output_file, explained_variance, cumulative_variance, pca_component_1, pca_component_2 = perform_pca(
            csv_file, target_column, n_components
        )

        return jsonify({
            "message": "PCA 处理成功",
            "outputFile": output_file,
            "explainedVariance": explained_variance,
            "cumulativeVariance": cumulative_variance,
            "pcaComponentOne": pca_component_1,
            "pcaComponentTwo": pca_component_2,
            "code": "200"
        })

    except Exception as e:
        return jsonify({"error": str(e), "message": f"模型训练失败：{str(e)}", "code": "500"}), 500



#XGB
@app.route('/xgb', methods=['POST'])
def detect_XGB():
    try:
        data = request.get_json()
        if not data:
            return jsonify({"error": "请求数据为空", "code": "400"}), 400

        # **获取参数**
        xlsx_file = data.get("xlsxFile")
        select_feature = data.get("selectFeature")
        target_feature = data.get("targetFeature")

        # **检查参数完整性**
        if not xlsx_file or not select_feature or not target_feature:
            return jsonify({"error": "缺少必要参数", "code": "400"}), 400

        # **检查文件是否存在**
        if not os.path.exists(xlsx_file):
            return jsonify({"error": "文件不存在", "code": "400"}), 400

        # **调用 XGBoost 计算特征重要性**
        output_file, sorted_importance = plot_feature_importance(xlsx_file, select_feature, target_feature)

        # **构造返回 JSON**
        return jsonify({
            "message": "XGBoost 特征重要性计算成功",
            "outputFile": output_file,
            "topFifthFeatures": sorted_importance[:5],  # 返回前 5 个最重要的特征
            "allFeatures": sorted_importance,
            "code": "200"
        })

    except ValueError as ve:
        return jsonify({
            "error": str(ve),
            "message": "数据处理异常",
            "code": "400"
        }), 400

    except Exception as e:
        return jsonify({
            "error": str(e),
            "message": "服务器内部错误",
            "code": "500"
        }), 500


#RF
@app.route('/rf', methods=['POST'])
def detect_RF():
    try:
        data = request.get_json()
        if not data:
            return jsonify({"error": "请求数据为空", "code": "400"}), 400

        # 获取参数
        xlsx_file = data.get("xlsxFile")
        select_feature = data.get("selectFeature")
        target_feature = data.get("targetFeature")

        # **检查参数完整性**
        if not xlsx_file or not select_feature or not target_feature:
            return jsonify({"error": "缺少必要参数", "code": "400"}), 400

        # **检查文件是否存在**
        if not os.path.exists(xlsx_file):
            return jsonify({"error": "文件不存在", "code": "400"}), 400

        # **调用随机森林计算特征重要性**
        output_file, sorted_importance = plot_feature_importance_rf(xlsx_file, select_feature, target_feature)

        # **构造返回 JSON**
        return jsonify({
            "message": "随机森林特征重要性计算成功",
            "outputfile": output_file,
            #"top_5_features": sorted_importance[:5],  # 返回前 5 个最重要的特征
            "topFifthFeatures": sorted_importance[:5],  # 返回前 5 个最重要的特征
            "allfeatures": sorted_importance,
            "code": "200"
        })

    except ValueError as ve:
        return jsonify({
            "error": str(ve),
            "message": "数据处理异常",
            "code": "400"
        }), 400

    except Exception as e:
        return jsonify({
            "error": str(e),
            "message": "服务器内部错误",
            "code": "500"
        }), 500









#以下是新接口
# 极限梯度增强树
# @app.route('/limit/tree', methods=['POST'])
# def detect_limit_tree():
#     try:
#         # 获取请求的 JSON 数据
#         data = request.get_json()
#         if not data:
#             return jsonify({"error": "没有收到有效的请求数据"}), 400
#
#         # 获取参数
#         excel_file_path = data.get("excelFilePath")
#         model_save_path = data.get("modelSavePath")
#         input_features = data.get("inputFeatures")
#         target_feature = data.get("targetFeature")
#         param_grid = data.get("paramGrid")
#
#         # 检查必要的参数是否存在
#         if not all([excel_file_path, model_save_path, input_features, target_feature, param_grid]):
#             return jsonify({"error": "缺少必要参数"}), 400
#
#         # 调用模型训练和预测函数
#         best_params, final_mse_test, final_r2_test, final_mse_train, final_r2_train, \
#             encoded_mapping, y_pred_final_train, y_train, y_pred_final_test, y_test, model_pkl_path = XGB_reg_label(
#             excel_file_path=excel_file_path,
#             model_save_path=model_save_path,
#             input_features=input_features,
#             target_feature=target_feature,
#             param_grid=param_grid,
#             save_model=True
#         )
#
#         # 返回结果
#         return jsonify({
#             "bestParams": best_params,
#             "finalMseTest": final_mse_test,
#             "finalR2Test": final_r2_test,
#             "finalMseTrain": final_mse_train,
#             "finalR2Train": final_r2_train,
#             "encodedMapping": encoded_mapping,
#             "yPredFinalTrain": y_pred_final_train,
#             "yTrain": y_train,
#             "yPredFinalTest": y_pred_final_test,
#             "yTest": y_test,
#             "modelPklPath": model_pkl_path  # 返回模型保存路径
#         })
#
#     except Exception as e:
#         # 错误日志
#         return jsonify({
#             "error": str(e),
#             "message": "模型训练失败：" + str(e),
#             "code": "505",
#         })


# 集成增强模型
@app.route('/integrat/enhance', methods=['POST'])
def detect_integrat_enhance():
    try:
        # 获取请求的 JSON 数据
        data = request.get_json()
        if not data:
            return jsonify({"error": "没有收到有效的请求数据"}), 400

        # 获取请求参数
        excel_file_path = data.get('excelFilePath')
        model_save_path = data.get('modelSavePath')
        input_features = data.get('inputFeatures')
        target_feature = data.get('targetFeature')

        # 检查传入的参数是否有效
        if not excel_file_path or not model_save_path or not input_features or not target_feature:
            return jsonify({"error": "缺少必要的参数"}), 400

        # 调用模型训练和预测函数
        booster, mse, r2, mse_tr, r2_tr, encoded_mapping, base_preds, base_preds_te, y_pred_tr, y_train, y_pred, y_test, model_file_path = ensemble_model(
            excel_file_path=excel_file_path,
            model_save_path=model_save_path,
            input_features=input_features,
            target_feature=target_feature,
            save_model=True
        )

        # 返回结果
        return jsonify({
            "mseTrain": mse_tr,
            "r2Train": r2_tr,
            "mseTest": mse,
            "r2Test": r2,
            "encodedMapping": encoded_mapping,
            "basePreds": base_preds.to_dict(orient='records'),  # 将DataFrame转换为列表
            "basePredsTe": base_preds_te.to_dict(orient='records'),  # 将DataFrame转换为列表
            "yPredTr": y_pred_tr.tolist(),  # 转换为列表
            "yTrain": y_train.tolist(),  # 转换为列表
            "yPred": y_pred.tolist(),  # 转换为列表
            "yTest": y_test.tolist(),  # 转换为列表
            "modelFilePath": model_file_path  # 返回模型保存的文件路径
        })

    except Exception as e:
        return jsonify({
            "error": str(e),
            "message": f"模型训练失败：{str(e)}",
            "code": "500",
        })


# 自编码特征筛选模型
# @app.route('/own/code/feature/select', methods=['POST'])
# def detect_own_feature_select():
#     try:
#         data = request.get_json()
#         if not data:
#             return jsonify({"error": "没有收到有效的请求数据"}), 400
#
#         # 提取参数
#         excel_file_path = data.get('excelFilePath')
#         model_save_path = data.get('modelSavePath', "model.pkl")
#         input_features = data.get('inputFeatures')
#         target_feature = data.get('targetFeature')
#
#         if not excel_file_path or not model_save_path or not input_features or not target_feature:
#             return jsonify({"error": "缺少必要的参数"}), 400
#
#         # 调用模型
#         result = XGB_reg_label_autoencoder_base(
#             excel_file_path=excel_file_path,
#             model_save_path=model_save_path,
#             input_features=input_features,
#             target_feature=target_feature,
#             save_model=True
#         )
#
#         return jsonify(result)  # 直接返回字典，避免解包错误
#
#     except Exception as e:
#         return jsonify({
#             "error": str(e),
#             "message": f"模型训练失败：{str(e)}",
#             "code": "500",
#         })



if __name__ == '__main__':
    # 启动 Flask 应用
    app.run(debug=True, host='0.0.0.0', port=5001)
